import { Injectable } from '@nestjs/common';
import { Coupon_Create_Dto, Coupon_Update_Dto, Coupon_Web_Find_Dto } from './assets/coupon.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Coupon } from './assets/coupon.entity';
import { EntityManager, Repository } from 'typeorm';
import { Coupon_Find_Dto } from './assets/coupon.dto';
import { util_Db_Add, util_Db_Delete, util_Db_PageList } from '@/common/util/db';
import { CouponSort } from '../couponSort/assets/couponSort.entity';
import {
  Constant_Enum_Enum_CouponUserClient_Status,
  Constant_Enum_Enum_Coupon_CouponStatus,
  Constant_Enum_Enum_Coupon_Scope,
  Constant_Enum_Enum_Coupon_TimeLimitType,
  Constant_Enum_Enum_Coupon_UseStatus,
} from '@/common/constants/enum';
import { Class_HttpException_Base } from '@/common/classes/httpException';
import { IRequest } from '@/common/typeScripts';
import { Others_PageClass_Base } from '@/common/others/pageClass';
import { UserClient_Service } from '../userClient/userClient.service';
import { CouponUserClient_Service } from '../couponUserClient/couponUserClient.service';
import { CouponUserClient } from '../couponUserClient/assets/couponUserClient.entity';

@Injectable()
export class Coupon_Service {
  constructor(
    @InjectRepository(CouponUserClient)
    private couponUserClient_Repository: Repository<CouponUserClient>,
    @InjectRepository(Coupon)
    private coupon_Repository: Repository<Coupon>,
    @InjectRepository(CouponSort)
    private couponSort_Repository: Repository<CouponSort>,
    private userClient_Service: UserClient_Service,
    private couponUserClient_Service: CouponUserClient_Service,
    private entityManager: EntityManager,
  ) {}

  async coupon_Create(body: Coupon_Create_Dto) {
    return await this.entityManager.transaction(async (manage) => {
      if (body.timeLimitType == Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_ValidDays) {
        body.fixedTimeStart = null;
        body.fixedTimeEnd = null;
      }
      const couponSorts: CouponSort[] = [];
      body.couponSortIds.map((item) => {
        couponSorts.push(this.couponSort_Repository.create({ id: item }));
      });
      const couponEnpitity = this.coupon_Repository.create({
        couponSorts: couponSorts,
        couponName: body.couponName,
        couponRemark: body.couponRemark,
        couponType: body.couponType,
        reduceMoney: body.reduceMoney,
        reducePrice: body.reducePrice,
        discount: body.discount,
        couponScope: body.couponScope,
        timeLimitType: body.timeLimitType,
        fixedTimeStart: body.fixedTimeStart,
        fixedTimeEnd: body.fixedTimeEnd,
        exchangeCode: body.exchangeCode,
        couponPlatformType: body.couponPlatformType,
        couponStatus: body.couponStatus,
        validDays: body.validDays,
        useStatus: body.useStatus,
      });
      await manage.save(Coupon, couponEnpitity);
      return '新增成功';
    });
  }
  async coupon_Update(body: Coupon_Update_Dto) {
    console.log(body);
    return await this.entityManager.transaction(async (manage) => {
      if (body.timeLimitType == Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_ValidDays) {
        body.fixedTimeStart = null;
        body.fixedTimeEnd = null;
      }
      const couponSorts: CouponSort[] = [];
      body.couponSortIds.map((item) => {
        couponSorts.push(this.couponSort_Repository.create({ id: item }));
      });
      const couponEnpitity = this.coupon_Repository.create({
        couponSorts: couponSorts,
        couponName: body.couponName,
        couponRemark: body.couponRemark,
        couponType: body.couponType,
        reduceMoney: body.reduceMoney,
        reducePrice: body.reducePrice,
        discount: body.discount,
        couponScope: body.couponScope,
        timeLimitType: body.timeLimitType,
        fixedTimeStart: body.fixedTimeStart,
        fixedTimeEnd: body.fixedTimeEnd,
        exchangeCode: body.exchangeCode,
        couponPlatformType: body.couponPlatformType,
        couponStatus: body.couponStatus,
        useStatus: body.useStatus,
        validDays: body.validDays,
        id: body.id,
      });
      await manage.save(Coupon, couponEnpitity);
      return '修改成功';
    });
  }
  async coupon_Admin_FindByPage(query: Coupon_Find_Dto) {
    const couponSortsSubQuery = this.coupon_Repository
      .createQueryBuilder('coupon')
      .select([
        'coupon.id AS couponId',
        `JSON_ARRAYAGG(
      JSON_OBJECT("id", couponSorts.id, "name", couponSorts.couponSortName)
    ) AS couponSorts`,
      ])
      .leftJoin('coupon.couponSorts', 'couponSorts')
      .groupBy('coupon.id');

    const couponProductsSubQuery = this.coupon_Repository
      .createQueryBuilder('coupon')
      .select([
        'coupon.id AS couponId',
        `JSON_ARRAYAGG(
      JSON_OBJECT(
        "id", product.id,
        "name", product.productName,
        "platFormName", platform.platFormName,
        "platFormId", platform.id
      )
    ) AS couponProducts`,
      ])
      .leftJoin('coupon.couponProducts', 'couponProducts')
      .leftJoin('couponProducts.platform', 'platform')
      .leftJoin('couponProducts.product', 'product')
      .groupBy('coupon.id');

    const mainQuery = this.coupon_Repository
      .createQueryBuilder('coupon')
      .leftJoin(`(${couponSortsSubQuery.getQuery()})`, 'couponSorts', 'couponSorts.couponId = coupon.id')
      .leftJoin(
        `(${couponProductsSubQuery.getQuery()})`,
        'couponProducts',
        'couponProducts.couponId = coupon.id',
      )
      .select([
        'coupon.id AS id',
        'coupon.couponName AS couponName',
        'coupon.couponRemark AS couponRemark',
        'coupon.couponType AS couponType',
        'coupon.reduceMoney AS reduceMoney',
        'coupon.reducePrice AS reducePrice',
        'coupon.discount AS discount',
        'coupon.couponScope AS couponScope',
        'coupon.timeLimitType AS timeLimitType',
        'coupon.fixedTimeStart AS fixedTimeStart',
        'coupon.fixedTimeEnd AS fixedTimeEnd',
        'coupon.exchangeCode AS exchangeCode',
        'coupon.validDays AS validDays',
        'coupon.couponPlatformType AS couponPlatformType',
        'coupon.useStatus AS useStatus',
        'coupon.couponStatus AS couponStatus',
        'couponSorts.couponSorts',
        'couponProducts.couponProducts',
      ]);

    const results = await util_Db_PageList<Coupon>({
      queryBuilder: mainQuery,
      query: {
        useStatus: Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_IsUse,
        'couponSorts.id': query.couponSortIds,
        size: query.size,
        page: query.page,
        couponName: query.couponName,
        couponType: query.couponType,
        couponScope: query.couponScope,
        exchangeCode: query.exchangeCode,
        couponPlatformType: query.couponPlatformType,
        couponStatus: query.couponStatus,
      },
      isRaw: true,
    });
    results.list = results.list.map((result) => {
      return {
        ...result,
        couponSorts: result.couponSorts.filter((sort) => sort.id !== null),
        couponProducts: result.couponProducts.filter((product) => product.id !== null),
      };
    });
    return results;
  }

  async coupon_FindOneById(id: number) {
    return await this.coupon_Repository
      .createQueryBuilder('coupon')
      .andWhere(`coupon.id = :id`, { id: id })
      .getOne();
  }

  async coupon_ChageStatus(id: string) {
    const result = await this.coupon_FindOneById(Number(id));
    if (!result) throw new Class_HttpException_Base('不存在该记录');
    result.couponStatus =
      result.couponStatus == Constant_Enum_Enum_Coupon_CouponStatus.Coupon_CouponStatus_NoSending
        ? Constant_Enum_Enum_Coupon_CouponStatus.Coupon_CouponStatuse_Sending
        : Constant_Enum_Enum_Coupon_CouponStatus.Coupon_CouponStatus_NoSending;
    await this.coupon_Repository.save(result);
    return '修改成功';
  }

  async coupon_StopUse(id: string) {
    const result = await this.coupon_FindOneById(Number(id));
    if (!result) throw new Class_HttpException_Base('不存在该记录');
    result.useStatus =
      result.useStatus == Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_IsUse
        ? Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_StopUse
        : Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_IsUse;
    await this.coupon_Repository.save(result);
    return '修改成功';
  }

  async coupon_Remove(id: number) {
    return await util_Db_Delete({
      findOne: () => this.coupon_FindOneById(id),
      id,
      repository: this.coupon_Repository,
    });
  }

  async coupon_Web_NoReceived(req: IRequest, query: Others_PageClass_Base) {
    const hasUser = await this.userClient_Service.userClient_WebUtil_isNewUser(req);
    const subQueryResults = await this.couponUserClient_Repository
      .createQueryBuilder('couponUserClient')
      .leftJoin('couponUserClient.coupon', 'coupon')
      .select(['coupon.id AS id'])
      .where('couponUserClient.userClientId = :userClientId', { userClientId: req.user.userId })
      .getRawMany();
    console.log(subQueryResults);

    const couponIds = subQueryResults.map((result) => result.id);
    const result = await util_Db_PageList<Coupon>({
      queryBuilder: this.coupon_Repository
        .createQueryBuilder('coupon')
        .leftJoin('coupon.couponUserClient', 'couponUserClient')
        .leftJoin('coupon.couponProducts', 'couponProducts')
        .leftJoin('couponProducts.platform', 'platform')
        .leftJoin('couponProducts.product', 'product')
        .where('coupon.useStatus = :useStatus', {
          useStatus: Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_IsUse,
        })
        .andWhere(hasUser ? '1=1' : 'coupon.couponScope != :couponScope', {
          couponScope: Constant_Enum_Enum_Coupon_Scope.Coupon_Scope_NewUser,
        })
        .andWhere('coupon.couponStatus = :couponStatus', {
          couponStatus: Constant_Enum_Enum_Coupon_CouponStatus.Coupon_CouponStatuse_Sending,
        })
        .andWhere(couponIds.length ? 'coupon.id NOT IN (:...couponIds)' : '1=1', { couponIds })
        .andWhere(
          `(coupon.timeLimitType = :validDays OR 
            (coupon.timeLimitType = :fixedTime AND 
             (coupon.fixedTimeEnd IS NULL OR coupon.fixedTimeEnd >= :fixedTimeEnd)))`,
          {
            validDays: Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_ValidDays,
            fixedTime: Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_FixedTime,
            fixedTimeEnd: new Date().getTime(),
          },
        )
        .select([
          'coupon.id AS id',
          'coupon.couponName AS couponName',
          'coupon.couponType AS couponType',
          'coupon.reduceMoney AS reduceMoney',
          'coupon.reducePrice AS reducePrice',
          'coupon.timeLimitType AS timeLimitType',
          'coupon.fixedTimeStart AS fixedTimeStart',
          'coupon.fixedTimeEnd AS fixedTimeEnd',
          'coupon.validDays AS validDays',
          'coupon.discount AS discount',
          `JSON_ARRAYAGG(
            JSON_OBJECT(
              'productId', product.id,
              'productName', product.productName,
              'platformId', platform.id,
              'platformName', platform.platformName
            )
          ) AS couponProducts`,
        ])
        .groupBy('coupon.id'),
      query: {
        size: query.size,
        page: query.page,
      },
      isRaw: true,
      getQuery: true,
    });
    return result;
  }

  async coupon_Web_MyCoupon(req: IRequest, query: Coupon_Web_Find_Dto) {
    let qb = this.couponUserClient_Repository
      .createQueryBuilder('couponuserclient')
      .leftJoin('couponuserclient.coupon', 'coupon')
      .leftJoin('coupon.couponProducts', 'couponProduct')
      .leftJoin('couponProduct.platform', 'platform')
      .leftJoin('couponProduct.product', 'product')
      .where('couponuserclient.userClientId = :userClientId', { userClientId: req.user.userId })
      .andWhere('couponuserclient.fixedTimeEnd >= :fixedTimeEnd', {
        fixedTimeEnd: new Date().getTime(),
      })
      .andWhere('couponuserclient.status = :status', {
        status: Constant_Enum_Enum_CouponUserClient_Status.ExCode_ExCodeValue_Use,
      })
      .select([
        'coupon.id AS id',
        'coupon.couponName AS couponName',
        'coupon.couponType AS couponType',
        'coupon.reduceMoney AS reduceMoney',
        'coupon.reducePrice AS reducePrice',
        'coupon.discount AS discount',
        'couponUserClient.fixedTimeStart AS fixedTimeStart',
        'couponUserClient.fixedTimeEnd AS fixedTimeEnd',
        `JSON_ARRAYAGG(
    JSON_OBJECT(
      'productId', product.id,
      'productName', product.productName,
      'platformId', platform.id,
      'platformName', platform.platformName
    )
  ) AS couponProducts`,
      ])
      .groupBy('couponuserclient.id');
    if (query.couponProductId) {
      qb = qb
        .andWhere('product.id = :productId', { productId: query.couponProductId })
        .andWhere('couponUserClient.fixedTimeStart >= :fixedTimeStart', {
          fixedTimeStart: new Date().getTime(),
        });
    }
    const result = await util_Db_PageList<CouponUserClient>({
      queryBuilder: qb,
      isRaw: true,
      query: {
        size: query.size,
        page: query.page,
      },
      getQuery: true,
    });
    return result;
  }

  async coupon_Web_receive(req: IRequest) {
    const hasUser = await this.userClient_Service.userClient_WebUtil_isNewUser(req);
    const subQueryResults = await this.couponUserClient_Repository
      .createQueryBuilder('couponUserClient')
      .leftJoinAndSelect('couponUserClient.coupon', 'coupon')
      .select(['coupon.id AS id'])
      .where('couponUserClient.userClientId = :userClientId', { userClientId: req.user.userId })
      .getRawMany();
    const couponIds = subQueryResults.map((result) => result.id);
    const coupons = await this.coupon_Repository
      .createQueryBuilder('coupon')
      .leftJoinAndSelect('coupon.couponUserClient', 'couponUserClient')
      .where('coupon.couponStatus = :couponStatus', {
        couponStatus: Constant_Enum_Enum_Coupon_CouponStatus.Coupon_CouponStatuse_Sending,
      })
      .andWhere(hasUser ? '1=1' : 'coupon.couponScope != :couponScope', {
        couponScope: Constant_Enum_Enum_Coupon_Scope.Coupon_Scope_NewUser,
      })
      .andWhere('coupon.useStatus = :useStatus', {
        useStatus: Constant_Enum_Enum_Coupon_UseStatus.Coupon_UseStatus_IsUse,
      })
      .andWhere(couponIds.length ? 'coupon.id NOT IN (:...couponIds)' : '1=1', { couponIds })
      .andWhere(
        `(coupon.timeLimitType = :validDays OR 
          (coupon.timeLimitType = :fixedTime AND 
           (coupon.fixedTimeEnd IS NULL OR coupon.fixedTimeEnd >= :fixedTimeEnd)))`,
        {
          validDays: Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_ValidDays,
          fixedTime: Constant_Enum_Enum_Coupon_TimeLimitType.Coupon_TimeLimitType_FixedTime,
          fixedTimeEnd: new Date().getTime(),
        },
      )
      .getMany();
    if (coupons.length == 0) throw new Class_HttpException_Base('没有更多可领取的优惠券');
    const couponUserClients = this.couponUserClient_Service.couponUserClient_Util_Create({
      userClient: req.user.userId,
      coupons,
    });
    await util_Db_Add({
      createDto: couponUserClients,
      repository: this.couponUserClient_Repository,
    });
    // const couponIdsd = coupons.map((item) => {
    //   return item.id;
    // });
    // console.log(couponIdsd);
    // await this.couponUserClient_Repository.save();
    // await this.coupon_Repository
    //   .createQueryBuilder()
    //   .relation(Coupon, 'userClient')
    //   .of(couponIdsd)
    //   .add(user.id);
    return '领取成功';
  }
}
